//
//  WYWSqliteModelTool.m
//  SQlite
//
//  Created by Mr.Run on 2017/11/13.
//  Copyright © 2017年 Mr.Run. All rights reserved.
//

#import "WYWSqliteModelTool.h"
#import "WYWModelTool.h"
#import "WYWSqliteTool.h"
#import "WYWTableTool.h"

@implementation WYWSqliteModelTool

+(BOOL)createTable:(Class)cls uid:(NSString *)uid{
    
    NSString *tableName = [WYWModelTool tableName:cls];
    
    if (![cls respondsToSelector:@selector(primaryKey)]) {
        NSLog(@"%s~~~%d~~~如果要操作数据库必须实现 +(NSString *)primaryKey 方法",__func__,__LINE__);
        return NO;
    }
    
    NSString *primaryKey = [cls primaryKey];
    
    NSString *createTableSql = [NSString stringWithFormat:@"create table if not exists %@(%@, primary key(%@))", tableName, [WYWModelTool columnNamesAndTypesStr:cls], primaryKey];
    
    return [WYWSqliteTool deal:createTableSql uid:uid];
}

+(BOOL)isTableRequiredUpdated:(Class)cls uid:(NSString *)uid{
    
    NSArray *modelNames = [WYWModelTool allTableSortedIvarNames:cls];
    NSArray *tableNames = [WYWTableTool tableSortedColumnNames:cls uid:uid];
    
    return ![modelNames isEqualToArray:tableNames];
}

+(BOOL)updateTable:(Class)cls uid:(NSString *)uid{
    
    NSString *tmpTableName = [WYWModelTool tmpTableName:cls];
    NSString *tableName = [WYWModelTool tableName:cls];
    if (![cls respondsToSelector:@selector(primaryKey)]) {
        NSLog(@"%s~~~%d~~~如果要操作数据库必须实现 +(NSString *)primaryKey 方法",__func__,__LINE__);
        return NO;
    }
    
    NSMutableArray *execSqls = [NSMutableArray array];
    NSString *primaryKey = [cls primaryKey];
    
    NSString *createTableSql = [NSString stringWithFormat:@"create table if not exists %@(%@, primary key(%@));", tmpTableName, [WYWModelTool columnNamesAndTypesStr:cls], primaryKey];
    [execSqls addObject:createTableSql];
    NSString *insertPrimaryKeyData = [NSString stringWithFormat:@"insert into %@(%@) select %@ from %@", tmpTableName, primaryKey, primaryKey, tableName];
    [execSqls addObject:insertPrimaryKeyData];
    NSArray *oldNames = [WYWTableTool tableSortedColumnNames:cls uid:uid];
    NSArray *newNames = [WYWModelTool allTableSortedIvarNames:cls];
    NSDictionary *newNameToOldNameDic = [NSDictionary dictionary];
    if ([cls respondsToSelector:@selector(newNameToOldNameDic)]) {
        newNameToOldNameDic = [cls newNameToOldNameDic];
    }
    
    for (NSString *columnName in newNames) {
        
        NSString *oldName = columnName;
        
        if ([newNameToOldNameDic[columnName] length] != 0 && [oldNames containsObject:newNameToOldNameDic[oldName]]) {
            oldName = newNameToOldNameDic[columnName];
        }
        
        if ((![oldNames containsObject:columnName] && ![oldNames containsObject:oldName]) || [columnName isEqualToString:primaryKey]) {
            continue;
        }
        
        NSString *updateSql = [NSString stringWithFormat:@"update %@ set %@ = (select %@ from %@ where %@.%@ = %@.%@)", tmpTableName, columnName ,oldName, tableName, tmpTableName, primaryKey, tableName, primaryKey];
        [execSqls addObject:updateSql];
    }
    
    NSString *deleteOldTable = [NSString stringWithFormat:@"drop table if exists %@", tableName];
    [execSqls addObject:deleteOldTable];
    NSString *renameTableName = [NSString stringWithFormat:@"alter table %@ rename to %@", tmpTableName, tableName];
    [execSqls addObject: renameTableName];
    
    return [WYWSqliteTool dealSqls:execSqls uid:uid];
}

+(BOOL)saveOrUpdateModel:(id)model uid:(NSString *)uid{
    Class cls = [model class];
    
    if (![WYWTableTool isTableExists:cls uid:uid]) {
        [self createTable:cls uid:uid];
    }
    
    if ([self isTableRequiredUpdated:cls uid:uid]) {
        BOOL resultSuccess = [self updateTable:cls uid:uid];
        if (!resultSuccess) {
            NSLog(@"%s~~~%d~~~更新数据库表结构失败",__func__,__LINE__);
            return NO;
        }
    }
    
    NSString *tableName = [WYWModelTool tableName:cls];
    if (![cls respondsToSelector:@selector(primaryKey)]) {
        NSLog(@"%s~~~%d~~~如果要操作数据库必须实现 +(NSString *)primaryKey 方法",__func__,__LINE__);
        return NO;
    }
    NSString *primaryKey = [cls primaryKey];
    id primaryValue = [model valueForKeyPath:primaryKey];
    NSString *checkSql = [NSString stringWithFormat:@"select * from %@ where %@ = '%@'", tableName, primaryKey, primaryValue];
    
    NSArray *result = [WYWSqliteTool querySql:checkSql uid:uid];
    
    NSArray *columnNames = [WYWModelTool classIvarNameTypeDic:cls].allKeys;
    
    NSMutableArray *values = [NSMutableArray array];
    
    for (NSString *columnName in columnNames) {
        id value = [model valueForKeyPath:columnName];
        
        if ([value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]]) {
            
            NSData *data = [NSJSONSerialization dataWithJSONObject:value options:NSJSONWritingPrettyPrinted error:nil];
            value = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
        }
        
        [values addObject:value];
    }
    
    NSInteger count = columnNames.count;
    NSMutableArray *setValueArray = [NSMutableArray array];
    
    for (int i=0; i<count; i++) {
        NSString *name = columnNames[i];
        id value = values[i];
        NSString *setStr = [NSString stringWithFormat:@"%@='%@'", name, value];
        [setValueArray addObject:setStr];
    }
    
    NSString *execSql = @"";
    if (result.count > 0) {
        execSql = [NSString stringWithFormat:@"update %@ set %@ where %@ = '%@'", tableName, [setValueArray componentsJoinedByString:@","], primaryKey, primaryValue];
    }else{
        execSql = [NSString stringWithFormat:@"insert into %@(%@) values('%@')", tableName, [columnNames componentsJoinedByString:@","], [values componentsJoinedByString:@"','"]];
    }
    
    return [WYWSqliteTool deal:execSql uid:uid];
    
}

+(BOOL)deleteModel:(id)model uid:(NSString *)uid{
    
    Class cls = [model class];
    NSString *tableName = [WYWModelTool tableName:cls];
    if (![cls respondsToSelector:@selector(primaryKey)]) {
        NSLog(@"%s~~~%d~~~如果要操作数据库必须实现 +(NSString *)primaryKey 方法",__func__,__LINE__);
        return NO;
    }
    NSString *primaryKey = [cls primaryKey];
    id primaryValue = [model valueForKeyPath:primaryKey];
    
    NSString *deleteSql = [NSString stringWithFormat:@"delete from %@ where %@ = '%@'", tableName, primaryKey, primaryValue];
    
    return [WYWSqliteTool deal:deleteSql uid:uid];
}

+(BOOL)deleteModel:(Class)cls whereStr:(NSString *)whereStr uid:(NSString *)uid{
    NSString *tableName = [WYWModelTool tableName:cls];
    NSString *deleteSql = [NSString stringWithFormat:@"delete from %@", tableName];
    if (whereStr.length > 0) {
        deleteSql = [deleteSql stringByAppendingFormat:@" where %@", whereStr];
    }
    
    return [WYWSqliteTool deal:deleteSql uid:uid];
}
    
+(BOOL)deleteModel:(Class)cls columnName:(NSString *)columnName relation:(ColumnNameToValueRelationType)relation value:(id)value uid:(NSString *)uid{
    
    NSString *tableName = [WYWModelTool tableName:cls];
    NSString *deleteSql = [NSString stringWithFormat:@"delete from %@ where %@ %@ %@", tableName, columnName, self.columnNameToValueRelationTypeDic[@(relation)], value];
    
    
    return [WYWSqliteTool deal:deleteSql uid:uid];
}

+(NSArray *)queryAllModels:(Class)cls uid:(NSString *)uid{
    
    NSString *tableName = [WYWModelTool tableName:cls];
    
    NSString *sql = [NSString stringWithFormat:@"select * from %@", tableName];
    NSArray <NSDictionary *>*result = [WYWSqliteTool querySql:sql uid:uid];
    
    return [self parseResults:result withClass:cls];
}

+(NSArray *)queryModels:(Class)cls columnName:(NSString *)columnName relation:(ColumnNameToValueRelationType)relation value:(id)value uid:(NSString *)uid{
    NSString *tableName = [WYWModelTool tableName:cls];
    NSString *sql = [NSString stringWithFormat:@"select * from %@ where %@ %@ %@", tableName, columnName, self.columnNameToValueRelationTypeDic[@(relation)], value];
    
    NSArray <NSDictionary *>*results = [WYWSqliteTool querySql:sql uid:uid];
    return [self parseResults:results withClass:cls];
}

+(NSArray *)queryModels:(Class)cls withSql:(NSString *)sql uid:(NSString *)uid{
    NSArray <NSDictionary *>*results = [WYWSqliteTool querySql:sql uid:uid];
    return [self parseResults:results withClass:cls];
}

+(NSArray *)parseResults:(NSArray <NSDictionary *>*)results withClass:(Class)cls{
    NSMutableArray *models = [NSMutableArray array];
    NSDictionary *nameTypeDic = [WYWModelTool classIvarNameTypeDic:cls];
    
    for (NSDictionary *modelDic in results) {
        id model = [[cls alloc]init];
        [models addObject:model];
        [modelDic enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
            NSString *type = nameTypeDic[key];
            id resultValue = obj;
            if ([type isEqualToString:@"NSArray"] || [type isEqualToString:@"NSDictionary"]) {
                
                NSData *data = [obj dataUsingEncoding:NSUTF8StringEncoding];
                resultValue = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
                
            }else if([type isEqualToString:@"NSMutableArray"] || [type isEqualToString:@"NSMutableDictionary"]){
                
                NSData *data = [obj dataUsingEncoding:NSUTF8StringEncoding];
                resultValue = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
                
            }
            [model setValue:resultValue forKeyPath:key];
        }];
    }
    return models;
}

+(NSDictionary *)columnNameToValueRelationTypeDic{
    return @{
      @(ColumnNameToValueRelationTypeMore):@">",
      @(ColumnNameToValueRelationTypeLess):@"<",
      @(ColumnNameToValueRelationTypeEqual):@"=",
      @(ColumnNameToValueRelationTypeMoreEqual):@">=",
      @(ColumnNameToValueRelationTypeLessEqual):@"<="
      };
}

@end
